package cn.zhx.xa.system.service.impl;


import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.zhx.xa.model.dto.user.LoginDto;
import cn.zhx.xa.model.dto.user.SysUserAddOrUpdateDto;
import cn.zhx.xa.model.dto.user.SysUserSearchDto;
import cn.zhx.xa.model.dto.user_role.AssignRoleDto;
import cn.zhx.xa.model.entity.SysMenu;
import cn.zhx.xa.model.entity.SysUser;
import cn.zhx.xa.model.entity.SysUserRole;
import cn.zhx.xa.model.vo.common.ResultCodeEnum;
import cn.zhx.xa.model.vo.index.LoginVo;
import cn.zhx.xa.model.vo.index.SysUserInfoVo;
import cn.zhx.xa.service.exception.BusinessException;
import cn.zhx.xa.system.dao.SysUserRoleDao;
import cn.zhx.xa.system.mapper.SysMenuMapper;

import cn.zhx.xa.system.dao.SysUserDao;
import cn.zhx.xa.system.service.SysUserService;
import cn.zhx.xa.utils.JwtUtils;
import cn.zhx.xa.system.utils.LockService;
import cn.zhx.xa.utils.PasswordEncoder;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jakarta.annotation.Resource;

import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.concurrent.TimeUnit;

import static cn.zhx.xa.model.constant.RedisKey.*;
import static cn.zhx.xa.utils.RegexPatterns.PASSWORD_REGEX;
import static cn.zhx.xa.utils.RegexPatterns.USER_ACCOUNT_REGEX;


@Service
public class SysUserServiceImpl implements SysUserService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private SysUserDao sysUserDao;

    @Resource
    private SysUserRoleDao sysUserRoleDao;

    @Resource
    private SysMenuMapper sysMenuMapper;

    @Resource
    private JwtUtils jwtUtils;

    @Resource
    private LockService lockService;


    @Override
    public LoginVo login(LoginDto loginDto) {
        //校验验证码
        validateCode(loginDto.getCaptcha(), loginDto.getCodeKey());

        // 验证用户名和密码是否符合规则
        if (!(loginDto.getUsername().matches(USER_ACCOUNT_REGEX) && loginDto.getPassword().matches(PASSWORD_REGEX))) {
            throw new BusinessException(ResultCodeEnum.LOGIN_ERROR);
        }

        // 根据用户名查询用户
        SysUser sysUser = sysUserDao.selectByUserName(loginDto.getUsername());
        if (sysUser == null) {
            throw new BusinessException(ResultCodeEnum.LOGIN_ERROR);
        }

        // 验证密码是否正确
        String inputPassword = loginDto.getPassword();
        if (!PasswordEncoder.matches(sysUser.getPassword(), inputPassword)) {
            throw new BusinessException(ResultCodeEnum.LOGIN_ERROR);
        }

        // 生成令牌，保存数据到Redis中
        String token = jwtUtils.createToken(sysUser.getId());
        stringRedisTemplate.opsForValue().set(USER_LOGIN + sysUser.getId(), token, TOKEN_EXPIRE_DAYS, TimeUnit.DAYS);
        // 保存用户信息到redis中
//        stringRedisTemplate.opsForValue().set(USER_INFO + sysUser.getId(), JSONUtil.toJsonStr(sysUser), TOKEN_EXPIRE_DAYS , TimeUnit.DAYS);

        // 构建响应结果对象
        LoginVo loginVo = new LoginVo();
        loginVo.setToken(token);
        loginVo.setRefresh_token("");

        // 返回
        return loginVo;
    }

    @Override
    public void logout(String token) {
        Long validUid = jwtUtils.getValidUid(token);
        if (validUid == null) {
            throw new BusinessException(ResultCodeEnum.LOGIN_AUTH);
        }
        // 删除redis中的token
        stringRedisTemplate.delete(USER_LOGIN + validUid);
        // 删除redis中的用户信息
//        stringRedisTemplate.delete(USER_INFO + validUid);
    }

    @Override
    public SysUserInfoVo getUserInfo(String token) {
        // 获取用户信息
        Long uid = jwtUtils.getValidUid(token);
        if (uid == null) {
            throw new BusinessException(ResultCodeEnum.LOGIN_ERROR);
        }

        // 判断redis中是否存在用户信息
//        String userInfo = stringRedisTemplate.opsForValue().get(USER_INFO + uid);
//        if(StringUtils.isNotEmpty(userInfo)) {
//            // 存在直接返回
//            return JSON.parseObject(userInfo, SysUserInfoVo.class);
//        }

        // 不存在则从数据库中获取
        SysUserInfoVo sysUserInfoVo = new SysUserInfoVo();
        SysUser sysUser = sysUserDao.selectById(uid);
        //获取用户菜单信息
        List<SysMenu> sysMenus = sysMenuMapper.selectListByUserId(uid);
        List<String> menus = sysMenus.stream().map(SysMenu::getComponent).toList();

        sysUserInfoVo.setMenus(menus);
        sysUserInfoVo.setAvatar(sysUser.getAvatar());
        sysUserInfoVo.setName(sysUser.getName());
        sysUserInfoVo.setId(String.valueOf(uid));

        // 保存到redis中
//        stringRedisTemplate.opsForValue().set(USER_INFO + uid, JSONUtil.toJsonStr(sysUserInfoVo), 30 , TimeUnit.MINUTES);
        return sysUserInfoVo;
    }


    @Override
    public Page<SysUser> findByPage(SysUserSearchDto sysUserSearchDto, Integer pageNum, Integer pageSize) {
        if (!ObjectUtil.isAllNotEmpty(pageNum, pageSize)) {
            throw new BusinessException(ResultCodeEnum.DATA_ERROR);
        }
        Page<SysUser> pageInfo = new Page<>(pageNum, pageSize);
        return sysUserDao.findByPage(pageInfo, sysUserSearchDto);

    }

    @Override
    public void saveSysUser(SysUserAddOrUpdateDto sysUser) {
        // 验证用户名和密码是否符合规则
        if (!(sysUser.getUsername().matches(USER_ACCOUNT_REGEX) && sysUser.getPassword().matches(PASSWORD_REGEX))) {
            throw new BusinessException(ResultCodeEnum.REGISTER_ERROR);
        }

        //加锁

        lockService.executeWithLock(sysUser.getUsername(), 10, TimeUnit.SECONDS, () -> {
            // 根据输入的用户名查询用户
            SysUser dbSysUser = sysUserDao.selectByUserName(sysUser.getUsername());
            if (dbSysUser != null) {
                throw new BusinessException(ResultCodeEnum.USER_NAME_IS_EXISTS);
            }

            // 对密码进行加密
            String password = sysUser.getPassword();
            String digestPassword = PasswordEncoder.encode(password);
            sysUser.setPassword(digestPassword);

            SysUser newSysUser = new SysUser();
            BeanUtils.copyProperties(sysUser, newSysUser);
            sysUserDao.save(newSysUser);
            return null;
        });

    }

    @Override
    public void updateSysUser(SysUserAddOrUpdateDto sysUserAddOrUpdateDto) {
        sysUserDao.updateSysUser(sysUserAddOrUpdateDto);
    }

    @Override
    public void deleteById(Long userId) {
        if (ObjectUtil.isEmpty(sysUserDao.getById(userId))) {
            throw new BusinessException(ResultCodeEnum.DATA_ERROR);
        }
        sysUserDao.removeById(userId);
    }

    @Override
    @Transactional
    public void doAssign(AssignRoleDto assignRoleDto) {
        // 删除之前用户所对应的所有角色数据
        sysUserRoleDao.deleteByUserId(assignRoleDto.getUserId());

        // 分配新的角色数据
        List<Long> roleIdList = assignRoleDto.getRoleIdList();
        roleIdList.forEach(roleId -> {
            SysUserRole sysUserRole = new SysUserRole();
            sysUserRole.setRoleId(roleId);
            sysUserRole.setUserId(assignRoleDto.getUserId());
            sysUserRoleDao.save(sysUserRole);
        });
    }

    @Override
    public void userRegister(String username, String password, String checkPassword) {
        // 验证用户名和密码是否符合规则
        if (!(username.matches(USER_ACCOUNT_REGEX) && password.matches(PASSWORD_REGEX) && checkPassword.matches(PASSWORD_REGEX))) {
            throw new BusinessException(ResultCodeEnum.REGISTER_ERROR);
        }
        if (!(password.equals(checkPassword))) {
            throw new BusinessException(ResultCodeEnum.PASSWORD_ERROR);
        }

        //加锁
        lockService.executeWithLock(username, 10, TimeUnit.SECONDS, () -> {
            // 根据输入的用户名查询用户
            SysUser dbSysUser = sysUserDao.selectByUserName(username);
            if (ObjectUtil.isNotEmpty(dbSysUser)) {
                throw new BusinessException(ResultCodeEnum.USER_NAME_IS_EXISTS);
            }
            SysUser newSysUser = new SysUser();
            // 对密码进行加密
            String digestPassword = PasswordEncoder.encode(password);
            newSysUser.setPassword(digestPassword);
            newSysUser.setUsername(username);
            //随机姓名
            newSysUser.setName(RandomUtil.randomString(10));
            //默认头像
            newSysUser.setAvatar("https://img0.baidu.com/it/u=3975847930,3483376293&fm=253&fmt=auto&app=138&f=JPEG?w=400&h=400");
            sysUserDao.save(newSysUser);
            return null;
        });
    }


    //校验验证码
    private void validateCode(String captcha, String codeKey) {
        // 从Redis中获取验证码
        String redisCode = stringRedisTemplate.opsForValue().get(USER_LOGIN_CODE + codeKey);
        //校验
        if (StrUtil.isEmpty(redisCode) || !StrUtil.equalsIgnoreCase(redisCode, captcha)) {
            throw new BusinessException(ResultCodeEnum.VALIDATECODE_ERROR);
        }
        // 验证通过删除redis中的验证码
        stringRedisTemplate.delete(USER_LOGIN_CODE + codeKey);
    }


}